package com.example.demo.config.shiro;

import com.example.demo.config.shiro.authc.RetryLimitHashedCredentialsMatcher;
import com.example.demo.config.shiro.authc.StatelessAuthcFilter;
import com.example.demo.config.shiro.authc.UserRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with Software Dept.
 * <p> {@code ShiroConfig}
 *
 * @author : tianbaolei
 * @date : 2020-06-15 17:30
 * Description:
 */
@Configuration
public class ShiroConfiguration {

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);

        Map<String, String> filterChainMap = new HashMap<>(32);

        Map<String, Filter> filterMap = new HashMap<>(8);
        // logout 登出，authc 权限验证，anon 允许匿名的url，login 登录页
        filterChainMap.put("/logout", "logout");
        filterChainMap.put("/public/**", "anon");
        filterChainMap.put("/403", "anon");
        filterChainMap.put("/**", "authc");
        // shiroFilter.setLoginUrl();
        // shiroFilter.setSuccessUrl();
        shiroFilter.setUnauthorizedUrl("/403");


        StatelessAuthcFilter statelessAuthcFilter = new StatelessAuthcFilter();
        filterMap.put("authc", statelessAuthcFilter);

        shiroFilter.setFilters(filterMap);
        shiroFilter.setFilterChainDefinitionMap(filterChainMap);
        return shiroFilter;
    }

    @Bean
    @Primary
    public DefaultWebSecurityManager securityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        List<Realm> realmList = new ArrayList<>();
        realmList.add(userRealm);
        securityManager.setRealms(realmList);

        // 设置session相关
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionValidationSchedulerEnabled(false);
        securityManager.setSessionManager(sessionManager);

        DefaultSubjectDAO subjectDAO = (DefaultSubjectDAO) securityManager.getSubjectDAO();
        ((DefaultSessionStorageEvaluator) subjectDAO.getSessionStorageEvaluator()).setSessionStorageEnabled(false);

        // 创建subject时不创建session
        securityManager.setSubjectFactory(new StatelessWebSubjectFactory());
        // securityManager.setCacheManager(cacheManager);
        return securityManager;
    }

    @Bean
    public UserRealm userRealm(RetryLimitHashedCredentialsMatcher credentialsMatcher) {
        UserRealm userRealm = new UserRealm();

        userRealm.setCredentialsMatcher(credentialsMatcher);
        return userRealm;
    }

    @Bean
    public RetryLimitHashedCredentialsMatcher credentialsMatcher(CacheManager cacheManager) {
        return new RetryLimitHashedCredentialsMatcher(cacheManager, "md5", 2, true);
    }

    @Bean
    public CacheManager cacheManager() {
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
        return cacheManager;
    }
}
